package com.ionehe.group.common.async.service;

import com.google.common.base.Throwables;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.ionehe.group.common.async.annotation.AsyncMethod;
import com.ionehe.group.common.async.model.Message;
import com.ionehe.group.common.async.model.MethodModel;
import com.ionehe.group.common.async.util.AsyncSerializeUtil;
import com.ionehe.group.common.notify.message.exception.AsyncException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;

/**
 * Copyright (c) 2021 ionehe.com
 * Date: 2021/4/21
 * Time: 1:22 下午
 *
 * @author 2021年 <a href="mailto:a@ionehe.com">秀</a>
 * 【异步消息消息处理核心实现类】
 */
@Component
@Slf4j
public class MessageHandle {
    private static final Map<String, MethodModel> METHOD_MODEL_MAP = new ConcurrentHashMap<>();


    @Autowired
    private ApplicationContext applicationContext;


    public void putMethod(Object object) {
        Class<?> asyncService = object.getClass();
        for (Method method : asyncService.getMethods()) {
            AsyncMethod asyncMethod = method.<AsyncMethod>getAnnotation(AsyncMethod.class);
            if (asyncMethod != null) {
                if ((method.getParameters()).length == 0) {
                    log.error("async method:{} parameter empty!", method.getName());
                    throw new AsyncException("async method parameter empty!");
                }
                if (METHOD_MODEL_MAP.containsKey(asyncMethod.tag())) {
                    log.error("async tag:{} duplication!!", asyncMethod.tag());
                    throw new DuplicateKeyException("async tag duplication!!");
                }
                MethodModel methodModel = new MethodModel(asyncService, method);
                METHOD_MODEL_MAP.put(asyncMethod.tag(), methodModel);

                log.info("async method register success, service:{},method:{}", asyncService.getName(), method.getName());
            }
        }
    }


    public Boolean handle(Message message) {
        try {
            MethodModel methodModel = METHOD_MODEL_MAP.get(message.getTag());
            if (methodModel == null) {
                log.error("method not register!!!!");
            }
            Object service = this.applicationContext.getBean(methodModel.getClazz());
            Method method = methodModel.getMethod();
            Object[] objects = (Object[]) AsyncSerializeUtil.deserialize(message.getBody());
            method.invoke(service, objects);
            log.info("handle message success! tag:{}", message.getTag());
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("handle message fail! tag:{},cause:{}", (message == null) ? null : message.getTag(), Throwables.getStackTraceAsString(e));
            return Boolean.FALSE;
        }
    }
}


